package com.yxsk.relay.job.endpoint.combine.auto.config.components;

import com.yxsk.relay.job.component.common.net.NetServer;
import com.yxsk.relay.job.component.common.net.NettyServer;
import com.yxsk.relay.job.component.common.net.handler.HttpServerHandler;
import com.yxsk.relay.job.component.common.net.handler.convert.CompressAbleMessageConvert;
import com.yxsk.relay.job.component.common.net.handler.convert.NetMessageConvert;
import com.yxsk.relay.job.component.common.net.handler.exception.GlobalNetServerExceptionHandler;
import com.yxsk.relay.job.component.common.net.handler.interceptor.RpcHandleInterceptor;
import com.yxsk.relay.job.component.common.net.handler.message.MessageServerHandler;
import com.yxsk.relay.job.component.common.net.pipeline.HttpServerPipelineFactory;
import com.yxsk.relay.job.component.common.net.serialization.JsonMessageEntitySerializer;
import com.yxsk.relay.job.component.common.protocol.caller.DefaultHttpClientFactory;
import com.yxsk.relay.job.component.common.protocol.caller.HttpRestfulRemoteCaller;
import com.yxsk.relay.job.component.common.protocol.caller.RemoteCaller;
import com.yxsk.relay.job.component.endpoint.context.RelayJobNetContextHolder;
import com.yxsk.relay.job.component.endpoint.facade.DefaultJobHeadman;
import com.yxsk.relay.job.component.endpoint.facade.JobHeadman;
import com.yxsk.relay.job.component.endpoint.facade.net.RelayJobEndpointFacadeHandler;
import com.yxsk.relay.job.component.endpoint.log.stream.LogStream;
import com.yxsk.relay.job.component.endpoint.net.HttpRestfulRpcHandleInterceptor;
import com.yxsk.relay.job.component.endpoint.net.RestfulGlobalNetExceptionHandler;
import com.yxsk.relay.job.endpoint.combine.auto.config.properties.RelayJobAdminConfigProperties;
import com.yxsk.relay.job.endpoint.combine.auto.config.properties.RelayJobSlaveConfigProperties;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;

/**
 * @Description
 * @Author 11376
 * @CreateTime 2019/9/14 22:34
 */
@Configuration
@AutoConfigureOrder(4)
public class NetServerConfig {

    @ConditionalOnMissingBean(NetServer.class)
    @Bean(initMethod = "start", destroyMethod = "stop")
    public NetServer netServer(RelayJobSlaveConfigProperties slaveConfigProperties, ChannelPipelineFactory pipelineFactory) {
        return new NettyServer(pipelineFactory, slaveConfigProperties.getPort());
    }

    @Bean
    public HttpServerHandler serverHandler(MessageServerHandler messageServerHandler) {
        List<RpcHandleInterceptor> handleInterceptors = new LinkedList<>();
        handleInterceptors.add(new HttpRestfulRpcHandleInterceptor());
        handleInterceptors.add(new RelayJobNetContextHolder.NetRequestContextInterceptor());

        return HttpServerHandler.builder()
                .exceptionHandler(exceptionHandler())
                .interceptors(handleInterceptors)
                .messageConvert(messageConvert())
                .messageServerHandler(messageServerHandler)
                .build();
    }

    @Bean
    public ChannelPipelineFactory pipelineFactory(HttpServerHandler serverHandler) {
        return new HttpServerPipelineFactory(serverHandler);
    }

    @Bean
    public GlobalNetServerExceptionHandler exceptionHandler() {
        return new RestfulGlobalNetExceptionHandler();
    }

    @Bean
    public NetMessageConvert messageConvert() {
        return new CompressAbleMessageConvert();
    }

    @Bean
    public MessageServerHandler messageServerHandler(JobHeadman jobHeadman) {
        return new RelayJobEndpointFacadeHandler(jobHeadman, new JsonMessageEntitySerializer());
    }

    @Bean
    public JobHeadman headman(RelayJobAdminConfigProperties adminConfigProperties, LogStream logStream) {
        DefaultJobHeadman headman = DefaultJobHeadman.builder()
                .adminConfig(adminConfigProperties)
                .logStream(logStream)
                .remoteCaller(remoteCaller())
                .taskExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()))
                .tasks(new ConcurrentHashMap<>(16, 0.75f))
                .build();
        headman.setResultCallback(headman.new JobResultCallback());
        return headman;
    }

    @Bean
    public RemoteCaller remoteCaller() {
        return HttpRestfulRemoteCaller.builder()
                .httpClientFactory(new DefaultHttpClientFactory())
                .messageConvert(new CompressAbleMessageConvert())
                .serializer(new JsonMessageEntitySerializer())
                .build();
    }

}
